﻿Imports System.Text.RegularExpressions

Module funciones
    Public variables As String = "[a-z]" 'Declaramos las variables que se pueden usar
    Public variablesEnUso(26) As Boolean 'Almacena las variables que se encuntran en las fórmulas
    Public proposicionesNaturales As Collection = New Collection
    Public reemplazoVariables As Collection = New Collection
    Public operadoresBin As String = "[\.+|\.*|\.=|\.>]"

    Function esFBF(ByVal cadena As String) As Boolean
        Dim chequeo As Boolean 'Almacena el estado de las pruebas
        Dim i As Integer
        Dim cadenaCorrecta As Boolean
        chequeo = True
        cadenaCorrecta = False
        If cadena.Length <> 0 Then
            While i < cadena.Length And chequeo
                If i = 0 Then 'Valida el primer caracter. Proposición: p
                    If (cadena(i) = "-" Or Regex.IsMatch(cadena(i), variables) Or cadena(i) = "(") Then 'Proposición: "p o q o r"
                        chequeo = True
                    Else
                        chequeo = False
                    End If
                Else  'posición de 2 a n 
                    Select Case True
                        Case Regex.IsMatch(cadena(i), variables) 'ingreso variable
                            If cadena(i - 1) = "-" Or cadena(i - 1) = "(" Or Regex.IsMatch(cadena(i - 1), operadoresBin) Then 'Proposición: "p o q o r"
                                chequeo = True
                            Else
                                chequeo = False
                            End If
                        Case cadena(i) = "("
                            If cadena(i - 1) = "-" Or Regex.IsMatch(cadena(i - 1), operadoresBin) Or cadena(i - 1) = "(" Then 'Proposición: "p o r o q"
                                chequeo = True
                            Else
                                chequeo = False
                            End If
                        Case Regex.IsMatch(cadena(i), operadoresBin)
                            If Regex.IsMatch(cadena(i - 1), variables) Or cadena(i - 1) = ")" Then 'Proposición: "p o q"
                                chequeo = True
                            Else
                                chequeo = False
                            End If
                        Case cadena(i) = "-"
                            If Regex.IsMatch(cadena(i - 1), operadoresBin) Or cadena(i - 1) = "(" Or cadena(i - 1) = "-" Then 'Proposición: "p o q o r"
                                chequeo = True
                            Else
                                chequeo = False
                            End If
                        Case cadena(i) = ")"
                            If Regex.IsMatch(cadena(i - 1), variables) Or cadena(i - 1) = ")" Then 'Proposición: "p o q"
                                chequeo = True
                            Else
                                chequeo = False
                            End If
                    End Select
                End If
                If i = cadena.Length - 1 Then
                    cadenaCorrecta = True
                End If
                i += 1
            End While
            If chequeo And parentesis(cadena) And cadenaCorrecta Then 'Proposición: "p y q y r"
                If cadena(cadena.Length - 1) = ")" Or Regex.IsMatch(cadena(cadena.Length - 1), variables) Then 'proposicion: "p o q"'
                    i = 0
                    Return True
                Else
                    i = 0
                    Return False
                End If
            Else
                i = 0
                Return False
            End If
        Else
            i = 0
            Return False
        End If
    End Function

    Function parentesis(ByRef cadena As String) As Boolean 'Verifica el equilibrio de los paréntesis en una fórmula
        Dim i As Integer
        i = 0
        Dim cantParentesis As Integer = 0
        For i = 0 To cadena.Length - 1
            If cadena(i) = "(" Then 'Proposición: p => q
                cantParentesis += 1
            End If
            If cadena(i) = ")" Then 'Proposición: p => q
                cantParentesis -= 1
            End If
        Next
        Return cantParentesis = 0
    End Function

    Function crearAsignaciones(ByVal v As Integer) As Object
        Dim matriz((2 ^ v - 1), (v - 1)) As Boolean 'Crea matriz con asignaciones
        Dim alt As Integer = (2 ^ v) / 2 'Alternancia entre valuaci'on de variables
        Dim cantV As Integer = 1 ' Cuenta la cant. de verdaderos
        Dim cantF As Integer = 1 ' Cuenta la cant. de falsos
        Dim f, c As Integer ' Declaro filas y columnas
        f = 0
        c = 0
        While f < v
            c = 0
            While c < (2 ^ v)
                If cantV <= alt - 1 Then
                    matriz(c, f) = True
                    cantV += 1
                Else
                    matriz(c, f) = False
                    cantF += 1
                End If
                If cantV = alt And cantF = alt Then ' Resetea los contadores cuando coloca la cant. de verdaderos y falsos que corresponden. Proposición: p ^ q
                    cantV = 0
                    cantF = 0
                End If
                c += 1
            End While
            f += 1
            alt = alt / 2
        End While
        Return matriz
    End Function

    Function getVarSinUso(ByRef arrayVarEnUso() As Boolean) As Char 'Devolver variables que no están en uso
        Dim i As Integer = 0
        While (i < arrayVarEnUso.Length) And (arrayVarEnUso(i) = True)
            If arrayVarEnUso(i) = False Then
                arrayVarEnUso(i) = True
            End If
            i += 1
        End While
        Return Char.ConvertFromUtf32(97 + i)
    End Function

    Function ValidarComillas(ByRef cadena As String) As Boolean 'Cuenta la cantidad de comillas ingresadas
        Dim comillas As Integer = 0
        Dim i As Integer
        For i = 0 To cadena.Length - 1
            If cadena(i) = "'" Then
                comillas += 1
            End If
        Next
        If (comillas Mod 2 = 0) Or comillas = 0 Then
            Return True
        Else
            Return False
        End If
    End Function

    Function identificarVariables(ByRef arrayVarEnUso As Array, ByRef cadena As String) As Integer 'Identifica las variables que están en uso en una fórmula y devuelve la cantidad
        Dim comillas As Integer = 0
        Dim i As Integer = 0
        Dim h As Integer = 0
        Dim enUso As Boolean = True
        Dim cantVarEnUso As Integer = 0
        For i = 0 To cadena.Length - 1
            If cadena(i) = "'" Then
                comillas += 1
            End If
            If Regex.IsMatch(cadena(i), variables) And (comillas Mod 2 = 0) Then
                h = 0
                enUso = False
                h = Asc(cadena(i))
                h = h - 97
                If arrayVarEnUso(h) <> True Then
                    arrayVarEnUso(h) = True
                    cantVarEnUso += 1
                End If
            End If
        Next
        Return cantVarEnUso
    End Function

    Function reemplazar(ByRef cadena As String, ByRef coleccionPropoLN As Collection) As String
        Dim i As Integer = 0
        Dim nuevaCadena As String = ""
        Dim copiaCadena As String = ""
        Dim proposicionNatural As String = ""
        Dim variableReemplazo As Char = ""
        Dim posicion As Point
        posicion.Y = 0
        While i < cadena.Length
            If cadena(i) <> "'" Then
                nuevaCadena += cadena(i)
            Else                    'si no es comilla
                i += 1
                Do Until (cadena(i) = "'")
                    proposicionNatural = proposicionNatural & cadena(i)
                    i += 1
                Loop
                coleccionPropoLN.Add(proposicionNatural)
                variableReemplazo = getVarSinUso(variablesEnUso)
                reemplazoVariables.Add(variableReemplazo)
                nuevaCadena += variableReemplazo
                Dim etiqueta As Label = New Label
                With etiqueta
                    .Name = "lblProposicion\" & variableReemplazo
                    .Text = variableReemplazo & ": " & proposicionNatural
                    .Location = posicion
                    posicion.Y += 20
                    frmPrincipal.tabFrases.Controls.Add(etiqueta)
                End With
            End If
            i += 1
        End While
        Return nuevaCadena
    End Function
    Function precedencia(ByVal operador As Char) As Integer
        Select Case True
            Case operador = "-"
                Return 3
            Case operador = "+" Or operador = "*"
                Return 2
            Case operador = "=" Or operador = ">"
                Return 1
            Case Else
                Return 0
        End Select
    End Function

    Function asociatividad(ByRef operador As Char) As Boolean
        If operador = "+" Or operador = "*" Or operador = "=" Or operador = ">" Then
            Return True   'asociatividad izquierda
        Else
            Return False  'asociatividad derecha
        End If
    End Function

    Function postfijo(ByVal cadena As String) As String
        Dim pila As Stack = New Stack
        Dim cola As Queue = New Queue
        Dim cadenaPostfijo As String = ""
        pila.Clear()
        cola.Clear()
        Dim i As Integer = 0
        For i = 0 To cadena.Length - 1
            Select Case True
                Case Regex.IsMatch(cadena(i), variables)
                    cola.Enqueue(cadena(i))
                Case cadena(i) = "("
                    pila.Push(cadena(i))
                Case Regex.IsMatch(cadena(i), operadoresBin) Or cadena(i) = "-"
                    If pila.Count = 0 Then
                        pila.Push(cadena(i))
                    Else
                        If pila.Peek <> "(" And (((precedencia(cadena(i)) <= precedencia(pila.Peek)) And asociatividad(cadena(i))) Or (precedencia(cadena(i)) < precedencia(pila.Peek) And Not asociatividad(cadena(i)))) Then
                            cola.Enqueue(pila.Pop)
                            pila.Push(cadena(i))
                        Else
                            pila.Push(cadena(i))
                        End If
                    End If
                Case cadena(i) = ")"
                    While pila.Peek <> "("
                        cola.Enqueue(pila.Pop)
                    End While
                    pila.Pop()
            End Select
        Next
        If pila.Count <> 0 Then
            While pila.Count > 0
                cola.Enqueue(pila.Pop)
            End While
        End If
        While cola.Count > 0
            cadenaPostfijo += cola.Dequeue
        End While
        Return cadenaPostfijo
    End Function
End Module
